--[[
    SpamBayes for Eso, a lightweight bayesian antispam for The Elder Scrolls Online
    Copyright @ 2010 Arnaud Dovi (@class101 at EU-MegaServer, EU-MegaServer, ad@heapoverflow.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
]]

--[[
$Rev:: 4                     $:  Revision of last commit
$Author:: ad@heapoverflow.co#$:  Author of last commit
$Date:: 2014-04-27 19:14:57 #$:  Date of last commit
$Eso:: 1.0.5                 $:  Client of the last tests
]]

----------------- GLOBALS ----------------
SpamBayes                             = {}
SpamBayes.xml                         = {}
------------------------------------------

local MAJOR_VERSION                   = "100003"
local MINOR_VERSION                   = tonumber(("$Rev: 4 $"):match("%d+"))
SpamBayes.MINOR_VERSION               = SpamBayes.MINOR_VERSION == nil and MINOR_VERSION or (MINOR_VERSION > SpamBayes.MINOR_VERSION and MINOR_VERSION or SpamBayes.MINOR_VERSION)

local function initFrames(db)
    local words           = 0
    local sb              = SpamBayes, lastValue, minWidth, minHeight, maxWidth, maxHeight, rectWidth, rectHeight
    local global          = "SpamBayes"
    local ddsBorder       = "SpamBayes/textures/border.dds"
    local ddsBackground   = "SpamBayes/textures/background.dds"
    local ddsSlider       = "SpamBayes/textures/slider.dds"
    local ddsSliderEdge   = "SpamBayes/textures/slideredge.dds"
    local ddsSliderBg     = "SpamBayes/textures/sliderbg.dds"
    local font            = "EsoUi/Common/Fonts/Univers57.otf"
    local titlefont       = "EsoUi/Common/Fonts/Univers67.otf|20|soft-shadow-thin"
    local frameGlobal     = CreateControl(nil, GuiRoot,        CT_TOPLEVELCONTROL)
    local frameHeader     = CreateControl(nil, frameGlobal,    CT_TOPLEVELCONTROL)
    local frameLog        = CreateControl(nil, frameGlobal,    CT_TOPLEVELCONTROL)
    local frameInfo       = CreateControl(nil, frameGlobal,    CT_TOPLEVELCONTROL)
    local frameFooter     = CreateControl(nil, frameGlobal,    CT_TOPLEVELCONTROL)
    local frameAbout      = CreateControl(nil, GuiRoot,        CT_TOPLEVELCONTROL)
    local frameHelp       = CreateControl(nil, GuiRoot,        CT_TOPLEVELCONTROL)
    local frameOption     = CreateControl(nil, GuiRoot,        CT_TOPLEVELCONTROL)
    local frameLogBuffer  = CreateControl(nil, frameLog,       CT_TEXTBUFFER)
    local sliderFrameLog  = CreateControl(nil, frameLog,       CT_SLIDER)
    local backdropHeader  = CreateControl(nil, frameHeader,    CT_BACKDROP)
    local backdropLog     = CreateControl(nil, frameLog,       CT_BACKDROP)
    local backdropInfo    = CreateControl(nil, frameInfo,      CT_BACKDROP)
    local backdropFooter  = CreateControl(nil, frameFooter,    CT_BACKDROP)
    local backdropAbout   = CreateControl(nil, frameAbout,     CT_BACKDROP)
    local backdropHelp    = CreateControl(nil, frameHelp,      CT_BACKDROP)
    local backdropOption  = CreateControl(nil, frameOption,    CT_BACKDROP)
    local backdropSlider  = CreateControl(nil, sliderFrameLog, CT_BACKDROP)
    local buttonLogo      = CreateControl(nil, frameHeader,    CT_BUTTON)
    local buttonGrip      = CreateControl(nil, frameLog,       CT_BUTTON)
    local buttonClose1    = CreateControl(nil, frameHeader,    CT_BUTTON)
    local buttonAbout     = CreateControl(nil, frameFooter,    CT_BUTTON)
    local buttonReset     = CreateControl(nil, frameOption,    CT_BUTTON)
    local backdropAbout2  = CreateControl(nil, buttonAbout,    CT_BACKDROP)
    local backdropReset   = CreateControl(nil, buttonReset,    CT_BACKDROP)
    local buttonHelp      = CreateControl(nil, frameFooter,    CT_BUTTON)
    local backdropHelp2   = CreateControl(nil, buttonHelp,     CT_BACKDROP)
    local buttonOption    = CreateControl(nil, frameFooter,    CT_BUTTON)
    local backdropOption2 = CreateControl(nil, buttonOption,   CT_BACKDROP)
    local buttonClear     = CreateControl(nil, frameFooter,    CT_BUTTON)
    local backdropClear   = CreateControl(nil, buttonClear,    CT_BACKDROP)
    local labelLogo       = CreateControl(nil, frameHeader,    CT_LABEL)
    local labelInfo       = CreateControl(nil, frameInfo,      CT_LABEL)
    local clipboard       = CreateControl(nil, frameGlobal,    CT_EDITBOX)
    local chkButton1Str   = CreateControl(nil, frameOption,    CT_LABEL)
    local chkButton2Str   = CreateControl(nil, frameOption,    CT_LABEL)
    local chkButton3Str   = CreateControl(nil, frameOption,    CT_LABEL)
    local chkButton4Str   = CreateControl(nil, frameOption,    CT_LABEL)
    local chkButton5Str   = CreateControl(nil, frameOption,    CT_LABEL)
    local helpText        = CreateControl(nil, frameHelp,      CT_TEXTBUFFER)
    local aboutText1      = CreateControl(nil, frameAbout,     CT_LABEL)
    local aboutText2      = CreateControl(nil, frameAbout,     CT_LABEL)
    local aboutText3      = CreateControl(nil, frameAbout,     CT_LABEL)
    local aboutText4      = CreateControl(nil, frameAbout,     CT_LABEL)
    local aboutText5      = CreateControl(nil, frameAbout,     CT_LABEL)
    local chkButton1      = CreateControlFromVirtual(nil, frameOption, "ZO_CheckButton")
    local chkButton2      = CreateControlFromVirtual(nil, frameOption, "ZO_CheckButton")
    local chkButton3      = CreateControlFromVirtual(nil, frameOption, "ZO_CheckButton")
    local chkButton4      = CreateControlFromVirtual(nil, frameOption, "ZO_CheckButton")
    local chkButton5      = CreateControlFromVirtual(nil, frameOption, "ZO_CheckButton")

    local function onUpdateSlider(self, value)
        if lastValue and value == lastValue then return end -- used to stop an uncontrolable flood
        lastValue = value
        local min, max = sliderFrameLog:GetMinMax()
        frameLogBuffer:SetScrollPosition(max - value)
    end

    local function onToggleSlider()
        if frameLogBuffer:IsHidden() then return end
        local totalmsg     = frameLogBuffer:GetNumHistoryLines()
        local displayedmsg = frameLogBuffer:GetNumVisibleLines()
        local scrollSize   = totalmsg - displayedmsg
        local scrollValue  = scrollSize - frameLogBuffer:GetScrollPosition() -- for a slider from bottom to top
        if totalmsg > displayedmsg then
            sliderFrameLog:SetMinMax(0, scrollSize)
            sliderFrameLog:SetValue(scrollValue)
            sliderFrameLog:SetAlpha(1)
            sliderFrameLog:SetMouseEnabled(true)
        else -- no slider needed
            sliderFrameLog:SetAlpha(0)
            sliderFrameLog:SetMouseEnabled(false)
        end
    end

    local function D(text)
        d("|c808080[SpamBayes] : "..text.."|r")
    end

    local function copy(text)
        clipboard:SetText(text)
        clipboard:CopyAllTextToClipboard()
    end

    local function closeFrame(this)
        if this == buttonClose1 then
            frameAbout:SetHidden(true)
            frameHelp:SetHidden(true)
            frameOption:SetHidden(true)
            return this:GetParent():GetParent():SetHidden(true)
        end
        return this:GetParent():SetHidden(true)
    end

    -- Workaround some controls not moving a movable parent (Buttons, TextBuffer, etc...)
    local function dragStart(this)
        frameGlobal:StartMoving()
    end
    local function dragStop(this)
        frameGlobal:StopMovingOrResizing()
    end

    -- Workaround the boring Anchor system (client automatically changing them, never seen this in WoW and Warhammer Online...)
    local function moveStop(this)
        local x, y = frameGlobal:GetScreenRect()
        frameGlobal:ClearAnchors()
        frameGlobal:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, x , y)
        db.anchors = { x , y }
    end

    -- Workaround the missing API StartSizing() and the buggy OnUpdate...
    local function resizeStart(this)
        local iW, iH = 0, 0
        local x, y = GetUIMousePosition()
        local oW = frameGlobal:GetWidth()
        local oH = frameGlobal:GetHeight()
        EVENT_MANAGER:RegisterForUpdate("SpamBayesResize", 10, function() -- 10ms
            local nX, nY = GetUIMousePosition()
            if (iW ~= x - nX) then
                onToggleSlider()
                iW = x - nX
                db.width = oW - iW
                frameGlobal:SetWidth(db.width)
                moveStop()
            end
            if (iH ~= y - nY) then
                onToggleSlider()
                iH = y - nY
                db.height = oH - iH
                frameGlobal:SetHeight(db.height)
                moveStop()
            end
        end)
    end
    local function resizeStop(this)
        EVENT_MANAGER:UnregisterForUpdate("SpamBayesResize")
    end

    local function UpdateButtonIsAddOnEnabled(self, button)
        ZO_CheckButton_OnClicked(self, button)
        local pressed = chkButton1:GetState()
        db.isAddOnEnabled = pressed == BSTATE_PRESSED and true or false
        D(db.isAddOnEnabled and "ON" or "OFF")
        sb.shutdown(false)
    end

    local function UpdateButtonColorSpammers(self, button)
        ZO_CheckButton_OnClicked(self, button)
        local pressed = chkButton2:GetState()
        db.filterColorSpammers = pressed == BSTATE_PRESSED and true or false
        D(db.filterColorSpammers and "Color filtering ON" or "Color filtering OFF")
    end

    local function UpdateButtonFriendsStatus(self, button)
        ZO_CheckButton_OnClicked(self, button)
        local pressed = chkButton3:GetState()
        db.ignoreFriendsStatusChange = pressed == BSTATE_PRESSED and true or false
        D(db.ignoreFriendsStatusChange and "Friends filtering ON" or "Friends filtering OFF")
    end

    local function UpdateButtonContextMenuPlayer(self, button)
        ZO_CheckButton_OnClicked(self, button)
        local pressed = chkButton4:GetState()
        db.contextMenuShowPlayer = pressed == BSTATE_PRESSED and true or false
        D(db.contextMenuShowPlayer and "Context menu show player ON" or "Context menu show player OFF")
    end

    local function UpdateButtonContextMenuClipboard(self, button)
        ZO_CheckButton_OnClicked(self, button)
        local pressed = chkButton5:GetState()
        db.clipboard = pressed == BSTATE_PRESSED and true or false
        D(db.clipboard and "Context menu clipboard ON" or "Context menu clipboard OFF")
    end

    local function updateCounters(w, wr)
        if w then
            words = words + w
        elseif wr then
            words = words - wr
        end
        labelInfo:SetText(("Total messages trained : %d Spam, %d Ham\nMessages classified : %d Spam, %d Ham, %d Unsure\nWords in database : %d"):format(db.classifierdb.nspam or 0, db.classifierdb.nham or 0, db.classifierdb.cspam or 0, db.classifierdb.cham or 0, db.classifierdb.cunsure or 0, words))
    end

    local function resetDb()
        if IsShiftKeyDown() and IsControlKeyDown() then
            db.worddb = {}
            words = 0
            db.classifierdb = { nham = 0, nspam = 0, cspam = 0, cham = 0, cunsure = 0, probcache = {}}
            updateCounters()
            D("The classifier database and statistics have been reset.")
        else
            D("WARNING ! You are about to reset the classifier and statistics database, hold the shift+ctrl keys down while clicking the reset button to confirm.")
        end
    end

    local function toggleAbout()
        if frameGlobal:IsHidden() then
            frameGlobal:SetHidden(false)
        end
        if not frameOption:IsHidden() then
            frameOption:SetHidden(true)
        end
        if not frameHelp:IsHidden() then
            frameHelp:SetHidden(true)
        end
        if not frameAbout:IsHidden() then return frameAbout:SetHidden(true) end
        frameAbout:SetHidden(false)
    end

    local function toggleHelp()
        if frameGlobal:IsHidden() then
            frameGlobal:SetHidden(false)
        end
        if not frameOption:IsHidden() then
            frameOption:SetHidden(true)
        end
        if not frameAbout:IsHidden() then
            frameAbout:SetHidden(true)
        end
        if not frameHelp:IsHidden() then return frameHelp:SetHidden(true) end
        frameHelp:SetHidden(false)
    end

    local function toggleOption()
        if frameGlobal:IsHidden() then
            frameGlobal:SetHidden(false)
        end
        if not frameHelp:IsHidden() then
            frameHelp:SetHidden(true)
        end
        if not frameAbout:IsHidden() then
            frameAbout:SetHidden(true)
        end
        if not frameOption:IsHidden() then return frameOption:SetHidden(true) end
        frameOption:SetHidden(false)
    end

    clipboard:SetMaxInputChars(10000)

    frameGlobal:SetMouseEnabled(true)
    frameGlobal:SetMovable(true)
    frameGlobal:SetDrawTier(DT_MEDIUM)
    frameGlobal:SetDrawLevel(2)
    frameGlobal:SetClampedToScreen(true)
    frameGlobal:SetHeight(db.height or 500)
    frameGlobal:SetWidth(db.width or 1024)
    frameGlobal:SetDimensionConstraints(365, 255, 0, 0)
    frameGlobal:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, unpack(db.anchors and db.anchors or {512, 250}))
    frameGlobal:SetHandler("OnMoveStop", moveStop)
    frameGlobal:SetHandler("OnShow", onToggleSlider)

    frameHeader:SetHeight(50)
    frameHeader:SetAnchor(TOPLEFT, frameGlobal, TOPLEFT, 0 , 0)
    frameHeader:SetAnchor(TOPRIGHT, frameGlobal, TOPRIGHT, 0 , 0)

	backdropHeader:SetAnchorFill(frameHeader)
	backdropHeader:SetEdgeColor(1, 1, 1, 1)
    backdropHeader:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropHeader:SetCenterColor(128/255, 128/255, 128/255, 1)
	backdropHeader:SetCenterTexture(ddsBackground, 16, 0)
    backdropHeader:SetInsets(5, 5, -5, -5)

    buttonLogo:SetNormalTexture("SpamBayes/textures/spambayes_logo.dds")
    buttonLogo:SetAnchor(CENTER, frameHeader, CENTER, -100, 0)
    buttonLogo:SetWidth(32)
    buttonLogo:SetHeight(32)
    buttonLogo:SetHandler("OnDragStart", dragStart)
    buttonLogo:SetHandler("OnDragStop", dragStop)

    labelLogo:SetText("SpamBayes Control Center")
    labelLogo:SetColor(1, 1, 1, 0.95)
    labelLogo:SetFont(titlefont)
    labelLogo:SetAnchor(BOTTOMLEFT, buttonLogo, BOTTOMRIGHT, 2, -4)

    buttonClose1:SetNormalTexture("SpamBayes/textures/spambayes_tint_close1.dds")
    buttonClose1:SetMouseOverTexture("SpamBayes/textures/spambayes_tint_close2.dds")
    buttonClose1:SetHeight(16)
    buttonClose1:SetWidth(16)
    buttonClose1:SetAnchor(TOPRIGHT, frameHeader, TOPRIGHT, -8, 8)
    buttonClose1:SetHandler("OnMouseUp", closeFrame)
    buttonClose1:SetDrawTier(DT_HIGH)
    buttonClose1:SetDrawLevel(2)

    sliderFrameLog:SetThumbTexture(ddsSlider, ddsSlider, ddsSlider, 32, 32, 0, 0, 1, 1)
    sliderFrameLog:SetAnchor(TOPRIGHT, frameLog, TOPRIGHT, -10, 8)
    sliderFrameLog:SetAnchor(BOTTOMRIGHT, frameLog, BOTTOMRIGHT, -10, -8)
    sliderFrameLog:SetOrientation(ORIENTATION_VERTICAL)
    sliderFrameLog:SetWidth(16)
    sliderFrameLog:SetValue(0)
    sliderFrameLog:SetValueStep(1)
    sliderFrameLog:SetEnabled(true)
    sliderFrameLog:SetMouseEnabled(true)
    sliderFrameLog:SetDrawTier(DT_HIGH)
    sliderFrameLog:SetDrawLevel(2)
    sliderFrameLog:SetAllowDraggingFromThumb(true)
    sliderFrameLog:SetHandler("OnValueChanged", onUpdateSlider)

	backdropSlider:SetAnchorFill(sliderFrameLog)
	backdropSlider:SetEdgeColor(1, 1, 1, 1)
    backdropSlider:SetEdgeTexture(ddsSliderEdge, 64, 8, 8, 0)
	backdropSlider:SetCenterColor(128/255, 128/255, 128/255, 1)
	backdropSlider:SetCenterTexture(ddsSliderBg, 8, 0)
    backdropSlider:SetInsets(0, 6, 0, -6)

    frameLog:SetAnchor(TOPRIGHT, frameHeader, BOTTOMRIGHT, 0, 1)
    frameLog:SetAnchor(BOTTOMLEFT, frameInfo, TOPLEFT, 0, -1)

    frameLogBuffer:SetMouseEnabled(true)
    frameLogBuffer:SetLinkEnabled(true)
    frameLogBuffer:SetMaxHistoryLines(100000)
    frameLogBuffer:SetAnchor(TOPLEFT, frameLog, TOPLEFT, 8, 8)
    frameLogBuffer:SetAnchor(BOTTOMRIGHT, frameLog, BOTTOMRIGHT, -28, -8)
    frameLogBuffer:SetFont(font.."|12")
    frameLogBuffer:SetHandler("OnLinkClicked", function(self, ...) return ZO_ChatSystem_OnLinkClicked(...) end) -- \esoui\ingame\chatsystem\chatsystem.lua, line 2540 -- linkData, linkText, button
    frameLogBuffer:SetHandler("OnDragStart", dragStart)
    frameLogBuffer:SetHandler("OnDragStop", dragStop)
    frameLogBuffer:SetHandler("OnMouseWheel", function(self, delta, ctrl, alt, shift)
        if sliderFrameLog:GetAlpha() == 1 then
            if delta == 1 then
                sliderFrameLog:SetValue(sliderFrameLog:GetValue() - 1)
            else
                sliderFrameLog:SetValue(sliderFrameLog:GetValue() + 1)
            end
        end
    end)

	backdropLog:SetAnchorFill(frameLog)
	backdropLog:SetEdgeColor(1, 1, 1, 1)
    backdropLog:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropLog:SetCenterColor(0, 0, 0, 150/255)
	backdropLog:SetCenterTexture(ddsBackground, 16, 0)
    backdropLog:SetInsets(5, 5, -5, -5)

    frameInfo:SetHeight(80)
    frameInfo:SetAnchor(BOTTOMLEFT, frameFooter, TOPLEFT, 0, -1)
    frameInfo:SetAnchor(BOTTOMRIGHT, frameFooter, TOPRIGHT, 0, -1)

	backdropInfo:SetAnchorFill(frameInfo)
	backdropInfo:SetEdgeColor(1, 1, 1, 1)
    backdropInfo:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropInfo:SetCenterColor(0, 0, 0, 150/255)
	backdropInfo:SetCenterTexture(ddsBackground, 16, 0)
    backdropInfo:SetInsets(5, 5, -5, -5)

    labelInfo:SetColor(120/255, 120/255, 120/255, 1)
    labelInfo:SetFont(font.."|12")
    labelInfo:SetAnchor(TOPLEFT, frameInfo, TOPLEFT, 8, 8)
    for k in pairs(db.worddb) do
        words = words + 1
    end
    updateCounters()
    
    frameFooter:SetHeight(50)
    frameFooter:SetAnchor(BOTTOMLEFT, frameGlobal, BOTTOMLEFT, 0 , 0)
    frameFooter:SetAnchor(BOTTOMRIGHT, frameGlobal, BOTTOMRIGHT, 0 , 0)

	backdropFooter:SetEdgeColor(1, 1, 1, 1)
    backdropFooter:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropFooter:SetCenterColor(128/255, 128/255, 128/255, 1)
	backdropFooter:SetCenterTexture(ddsBackground, 16, 0)
    backdropFooter:SetInsets(5, 5, -5, -5)
	backdropFooter:SetAnchorFill(frameFooter)

    buttonGrip:SetNormalTexture("SpamBayes/textures/grip.dds")
    buttonGrip:SetMouseOverTexture("SpamBayes/textures/grip2.dds")
    buttonGrip:SetWidth(16)
    buttonGrip:SetHeight(16)
    buttonGrip:SetHandler("OnMouseDown", resizeStart)
    buttonGrip:SetHandler("OnMouseUp", resizeStop)
    buttonGrip:SetAnchor(BOTTOMRIGHT, frameLog, BOTTOMRIGHT, -2, -2)
    buttonGrip:SetDrawTier(DT_HIGH)
    buttonGrip:SetDrawLevel(2)

    buttonAbout:SetFont(font.."|16")
    buttonAbout:SetVerticalAlignment(1)
    buttonAbout:SetText("About")
    buttonAbout:SetAnchor(BOTTOMRIGHT, frameFooter, BOTTOMRIGHT, -12, -8)
    buttonAbout:SetHeight(32)
    buttonAbout:SetWidth(54)
    buttonAbout:SetNormalFontColor(160/255, 160/255, 160/255, 1)
    buttonAbout:SetHandler("OnMouseUp", toggleAbout)
    buttonAbout:SetDrawTier(DT_HIGH)
    buttonAbout:SetDrawLevel(2)

	backdropAbout2:SetAnchorFill(buttonAbout)
	backdropAbout2:SetEdgeColor(1, 1, 1, 1)
    backdropAbout2:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropAbout2:SetCenterColor(40/255, 40/255, 40/255, 1)
	backdropAbout2:SetCenterTexture(ddsBackground, 16, 0)
    backdropAbout2:SetInsets(5, 5, -5, -5)

    buttonHelp:SetFont(font.."|16")
    buttonHelp:SetVerticalAlignment(1)
    buttonHelp:SetText("Help")
    buttonHelp:SetAnchor(BOTTOMRIGHT, buttonAbout, BOTTOMLEFT, -5, 0)
    buttonHelp:SetHeight(32)
    buttonHelp:SetWidth(50)
    buttonHelp:SetNormalFontColor(160/255, 160/255, 160/255, 1)
    buttonHelp:SetHandler("OnMouseUp", toggleHelp)
    buttonHelp:SetDrawTier(DT_HIGH)
    buttonHelp:SetDrawLevel(2)

	backdropHelp2:SetAnchorFill(buttonHelp)
	backdropHelp2:SetEdgeColor(1, 1, 1, 1)
    backdropHelp2:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropHelp2:SetCenterColor(40/255, 40/255, 40/255, 1)
	backdropHelp2:SetCenterTexture(ddsBackground, 16, 0)
    backdropHelp2:SetInsets(5, 5, -5, -5)

    buttonOption:SetFont(font.."|16")
    buttonOption:SetVerticalAlignment(1)
    buttonOption:SetText("Options")
    buttonOption:SetAnchor(BOTTOMRIGHT, buttonHelp, BOTTOMLEFT, -5, 0)
    buttonOption:SetHeight(32)
    buttonOption:SetWidth(64)
    buttonOption:SetNormalFontColor(160/255, 160/255, 160/255, 1)
    buttonOption:SetHandler("OnMouseUp", toggleOption)
    buttonOption:SetDrawTier(DT_HIGH)
    buttonOption:SetDrawLevel(2)

	backdropOption2:SetAnchorFill(buttonOption)
	backdropOption2:SetEdgeColor(1, 1, 1, 1)
    backdropOption2:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropOption2:SetCenterColor(40/255, 40/255, 40/255, 1)
	backdropOption2:SetCenterTexture(ddsBackground, 16, 0)
    backdropOption2:SetInsets(5, 5, -5, -5)

    buttonClear:SetFont(font.."|16")
    buttonClear:SetVerticalAlignment(1)
    buttonClear:SetText("Clear")
    buttonClear:SetAnchor(BOTTOMRIGHT, buttonOption, BOTTOMLEFT, -5, 0)
    buttonClear:SetHeight(32)
    buttonClear:SetWidth(54)
    buttonClear:SetNormalFontColor(160/255, 160/255, 160/255, 1)
    buttonClear:SetHandler("OnMouseUp", function() frameLogBuffer:Clear() onToggleSlider() end)
    buttonClear:SetDrawTier(DT_HIGH)
    buttonClear:SetDrawLevel(2)

	backdropClear:SetAnchorFill(buttonClear)
	backdropClear:SetEdgeColor(1, 1, 1, 1)
    backdropClear:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropClear:SetCenterColor(40/255, 40/255, 40/255, 1)
	backdropClear:SetCenterTexture(ddsBackground, 16, 0)
    backdropClear:SetInsets(5, 5, -5, -5)

    -- Tiers frames

    frameAbout:SetWidth(1024)
    frameAbout:SetHeight(260)
    frameAbout:SetAnchor(TOPLEFT, frameFooter, BOTTOMLEFT, 0, -5)
    frameAbout:SetAnchor(TOPRIGHT, frameFooter, BOTTOMRIGHT, 0, -5)
    frameAbout:SetClampedToScreen(true)
    frameAbout:SetMouseEnabled(true)
    frameAbout:SetHandler("OnDragStart", dragStart)
    frameAbout:SetHandler("OnDragStop", dragStop)

	backdropAbout:SetAnchorFill(frameAbout)
	backdropAbout:SetEdgeColor(1, 1, 1, 1)
    backdropAbout:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropAbout:SetCenterColor(12/255, 21/255, 50/255, 1)
	backdropAbout:SetCenterTexture(ddsBackground, 16, 0)
    backdropAbout:SetInsets(5, 5, -5, -5)

    frameHelp:SetWidth(1100)
    frameHelp:SetHeight(250)
    frameHelp:SetAnchor(TOPLEFT, frameFooter, BOTTOMLEFT, 0, -5)
    frameHelp:SetAnchor(TOPRIGHT, frameFooter, BOTTOMRIGHT, 0, -5)
    frameHelp:SetClampedToScreen(true)
    frameHelp:SetMouseEnabled(true)
    frameHelp:SetHandler("OnDragStart", dragStart)
    frameHelp:SetHandler("OnDragStop", dragStop)

	backdropHelp:SetAnchorFill(frameHelp)
	backdropHelp:SetEdgeColor(1, 1, 1, 1)
    backdropHelp:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropHelp:SetCenterColor(40/255, 46/255, 2/255, 1)
	backdropHelp:SetCenterTexture(ddsBackground, 16, 0)
    backdropHelp:SetInsets(5, 5, -5, -5)

    frameOption:SetWidth(300)
    frameOption:SetHeight(200)
    frameOption:SetAnchor(TOPRIGHT, frameFooter, BOTTOMRIGHT, 0, -5)
    frameOption:SetClampedToScreen(true)
    frameOption:SetMouseEnabled(true)
    frameOption:SetHandler("OnDragStart", dragStart)
    frameOption:SetHandler("OnDragStop", dragStop)

	backdropOption:SetAnchorFill(frameOption)
	backdropOption:SetEdgeColor(1, 1, 1, 1)
    backdropOption:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropOption:SetCenterColor(5/255, 39/255, 1/255, 1)
	backdropOption:SetCenterTexture(ddsBackground, 16, 0)
    backdropOption:SetInsets(5, 5, -5, -5)

    -- Options

    chkButton1:SetAnchor(TOPLEFT, frameOption, TOPLEFT, 8, 8)
    chkButton1:SetState(db.isAddOnEnabled and BSTATE_PRESSED or BSTATE_NORMAL, db.isAddOnEnabled and true or false)
    chkButton1:SetHandler("OnClicked", UpdateButtonIsAddOnEnabled)

    chkButton1Str:SetText("Enable SpamBayes")
    chkButton1Str:SetColor(1, 1, 1, 0.95)
    chkButton1Str:SetFont(font.."|14")
    chkButton1Str:SetAnchor(LEFT, chkButton1, RIGHT, 5, 0)

    chkButton2:SetAnchor(TOP, chkButton1, BOTTOM, 0, 5)
    chkButton2:SetState(db.filterColorSpammers and BSTATE_PRESSED or BSTATE_NORMAL, db.filterColorSpammers and true or false)
    chkButton2:SetHandler("OnClicked", UpdateButtonColorSpammers)

    chkButton2Str:SetText("Filter colors in colorful player messages")
    chkButton2Str:SetColor(1, 1, 1, 0.95)
    chkButton2Str:SetFont(font.."|14")
    chkButton2Str:SetAnchor(LEFT, chkButton2, RIGHT, 5, 0)

    chkButton3:SetAnchor(TOP, chkButton2, BOTTOM, 0, 5)
    chkButton3:SetState(db.ignoreFriendsStatusChange and BSTATE_PRESSED or BSTATE_NORMAL, db.ignoreFriendsStatusChange and true or false)
    chkButton3:SetHandler("OnClicked", UpdateButtonFriendsStatus)

    chkButton3Str:SetText("Filter friends logged ON/OFF ui messages")
    chkButton3Str:SetColor(1, 1, 1, 0.95)
    chkButton3Str:SetFont(font.."|14")
    chkButton3Str:SetAnchor(LEFT, chkButton3, RIGHT, 5, 0)

    chkButton4:SetAnchor(TOP, chkButton3, BOTTOM, 0, 5)
    chkButton4:SetState(db.contextMenuShowPlayer and BSTATE_PRESSED or BSTATE_NORMAL, db.contextMenuShowPlayer and true or false)
    chkButton4:SetHandler("OnClicked", UpdateButtonContextMenuPlayer)

    chkButton4Str:SetText("Add character name to context menu")
    chkButton4Str:SetColor(1, 1, 1, 0.95)
    chkButton4Str:SetFont(font.."|14")
    chkButton4Str:SetAnchor(LEFT, chkButton4, RIGHT, 5, 0)

    chkButton5:SetAnchor(TOP, chkButton4, BOTTOM, 0, 5)
    chkButton5:SetState(db.clipboard and BSTATE_PRESSED or BSTATE_NORMAL, db.clipboard and true or false)
    chkButton5:SetHandler("OnClicked", UpdateButtonContextMenuClipboard)

    chkButton5Str:SetText("Add copy to clipboard to context menu")
    chkButton5Str:SetColor(1, 1, 1, 0.95)
    chkButton5Str:SetFont(font.."|14")
    chkButton5Str:SetAnchor(LEFT, chkButton5, RIGHT, 5, 0)

    buttonReset:SetFont(font.."|16")
    buttonReset:SetVerticalAlignment(1)
    buttonReset:SetText("Reset database")
    buttonReset:SetAnchor(BOTTOMRIGHT, frameOption, BOTTOMRIGHT, -8, -8)
    buttonReset:SetHeight(32)
    buttonReset:SetWidth(120)
    buttonReset:SetNormalFontColor(160/255, 160/255, 160/255, 1)
    buttonReset:SetHandler("OnMouseUp", resetDb)
    buttonReset:SetDrawTier(DT_HIGH)
    buttonReset:SetDrawLevel(2)

	backdropReset:SetAnchorFill(buttonReset)
	backdropReset:SetEdgeColor(1, 1, 1, 1)
    backdropReset:SetEdgeTexture(ddsBorder, 128, 16, 16, 0)
	backdropReset:SetCenterColor(40/255, 40/255, 40/255, 1)
	backdropReset:SetCenterTexture(ddsBackground, 16, 0)
    backdropReset:SetInsets(5, 5, -5, -5)

    -- Helps

    helpText:SetAnchor(TOPLEFT, frameHelp, TOPLEFT, 8, 8)
    helpText:SetAnchor(BOTTOMRIGHT, frameHelp, BOTTOMRIGHT, -8, -8)
    helpText:SetMouseEnabled(true)
    helpText:SetHandler("OnDragStart", dragStart)
    helpText:SetHandler("OnDragStop", dragStop)
    helpText:SetFont(font.."|13")
    helpText:SetMaxHistoryLines(10)
    helpText:AddMessage("|c89bd6f- Unlike most antispams, SpamBayes has intelligence, it does not uses hardcoded string patterns of known spammers, you are not forced to download X update of the AddOn to stop Y spammer, but instead, it uses a powerful algorithm designed by a vaste community of geeks to calculate the weight of a phrase as a probability so by training X and Y message, you will be able to stop A, B, C messages.")
    helpText:AddMessage("|c989afc- Messages displayed in Red = Spam(unwanted), Green = Ham(wanted), and Blank = Unsure. Unlike most antispams, SpamBayes never totally hides a spam, it displays everything in the control center and the chat windows except spams (by default, messages higher than 90% probability).")
    helpText:AddMessage("|c989afc- The settings and the spam database are global to all characters and are stored in the folder \\Documents\\Elder Scrolls Online\\live[eu]\\SavedVariables\\SpamBayes.lua")
    helpText:AddMessage("|c89bd6f- The more you will train unique spams and hams and the more autonomous it will be and the more correct classification will be. If you train as Spam a message with links, make sure to also train as Ham messages with links because the links have many invisible words sent in the database.")
    helpText:AddMessage("|c89bd6f- It is better to keep a balanced number of messages learned or a number of ham slightly higher in preferring to teach him phrases containing the most words and hams identified greater than 50%.")
    helpText:AddMessage("|c989afc- Learning a chat message as ham or spam is done by right-clicking the playername in the chatwindow or this control center.")
    helpText:AddMessage("|c989afc- You will most likely train SpamBayes to catch Gold spams, but if you also train SpamBayes to catch guild messages, it will be very powerful at catching all of them, this is just an example, the possibilities are endless and are up to you =)")
    helpText:AddMessage("|c89bd6f- By default, the database is blank, all messages received are classified Unsure, you will have to teach to distinguish spam(unwanted) from a ham(wanted).")

    aboutText1:SetText("SpamBayes for The Elder Scrolls Online")
    aboutText1:SetColor(1, 1, 1, 1)
    aboutText1:SetFont(titlefont)
    aboutText1:SetAnchor(TOP, frameAbout, TOP, 0, 20)
    aboutText2:SetText("v"..MAJOR_VERSION.." build |c00ff00"..tostring(sb.MINOR_VERSION).."|r")
    aboutText2:SetColor(1, 1, 1, 1)
    aboutText2:SetFont(titlefont)
    aboutText2:SetAnchor(TOP, aboutText1, BOTTOM, 0, 10)
    aboutText3:SetText("|cc023ffby |c69ccf0Fathis Ules I|cc023ff, |cabd473@class101|cc023ff |cc023ff @ EU|r")
    aboutText3:SetAnchor(TOP, aboutText2, BOTTOM, 0, 10)
    aboutText3:SetFont(titlefont)
    aboutText4:SetText("|c018541Tamriel Fisherman's Guild")
    aboutText4:SetAnchor(TOP, aboutText3, BOTTOM, 0, 10)
    aboutText4:SetFont(titlefont)
    aboutText5:SetText("Uses an algorithm of probabilities converted from SpamBayes Python a spam filter developed since 2002\nwhich is a combination of work from Gary Robinson and Tim Peters and many contributers\nsee http://spambayes.sourceforge.net/background.html.\n\n(An integration of SpamBayes into Thunderbird3 exist, look for the plugin ThunderBayes++ I am maintaining for TB3)")
    aboutText5:SetHorizontalAlignment(TEXT_ALIGN_CENTER)
    aboutText5:SetAnchor(TOP, aboutText4, BOTTOM, 0, 16)
    aboutText5:SetFont(font.."|12")

    frameAbout:SetHidden(true)
    frameHelp:SetHidden(true)
    frameOption:SetHidden(true)
    frameGlobal:SetHidden(true)
    clipboard:SetHidden(true)
        
    sb.xml.frame           = frameGlobal
    sb.xml.oframe          = frameOption
    sb.xml.hframe          = frameHelp
    sb.xml.aframe          = frameAbout
    sb.xml.log             = function(text) frameLogBuffer:AddMessage(text) onToggleSlider() end
    sb.xml.updateCounters  = updateCounters
    sb.xml.clipboardCopy   = copy
    sb.xml.tip             = tooltip
end

SpamBayes.xml.init  = initFrames
